# LeetCode 179、最大数

# 一、题目描述

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

**注意:**输出结果可能非常大,所以你需要返回一个字符串而不是整数。

示例 1:

输入:nums = [10,2]
输出:"210"

示例 2:

输入:nums = [3,30,34,5,9]
输出:"9534330"

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 10^9

# 二、题目解析

# 三、参考代码

# 1、Java 代码

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// https://leetcode-cn.com/problems/largest-number/submissions/
class Solution {
    public String largestNumber(int[] nums) {

        // 先将 nums 转换为字符串数组的形式
        String[] strs = new String[nums.length];

        for(int i = 0 ; i < nums.length; i++){
           strs[i] = String.valueOf(nums[i]);
        }
        // 通过快速排序的方式,将字符串数组的每个字符按照约定的顺序进行排序
        quickSort(strs,0,strs.length - 1);

        // 如果 nums 中最大的数是 0 ,那么只需要显示 1 个 0 就行
        if (strs[strs.length - 1].equals("0")) {
            return "0";
        }

        // 再把字符串数组转字符串的形式
        StringBuilder ans = new StringBuilder();

        // 逆序输出结果就是最大的数
        for(int i = strs.length - 1 ; i >= 0 ; i--){
            String s = strs[i];
            ans.append(s);
        }    

        return ans.toString();
    }

    // 函数传入待排序数组 nums
    // 排序区间的左端点 left
    // 排序区间的右端点 right
    private void quickSort(String[] strs,int left, int right){

        // 如果 left 大于等于 right,说明该区间只有 1 个或者没有元素
        if( left >= right  ){
            // 无需再递归划分后再排序,直接返回
            return;
        }

        // 调用函数 partition,将 left 和 right 之间的元素划分为左右两部分
        int mid = partition(strs,left,right);

        // 划分之后,再对 mid 左侧的元素进行快速排序
        quickSort(strs,left,mid-1);

        // 划分之后,再对 mid 右侧的元素进行快速排序
        quickSort(strs,mid+1,right);
    }

    // 直接套之前的快速排序的代码进行修改
    // 原先的小于的含义指的是数值上的小于,比如 1  < 10 
    // 但现在的小于含义为:a + b 拼凑的字符串小于 b + a 拼凑的字符串
    // 比如 a = 1 ,b = 10 
    // 那么 a + b = “110”,b + a = “101”
    // 显然,b + a < a + b
    // 也就是说 a 应该放到 b 的后面来拼凑字符串
    private int partition(String[] strs, int left ,int right){

        // 经典快速排序的写法
        // 设置当前区间的第一个元素为基准元素
        String pivot = strs[left];

        // left 向右移动,right 向左移动,直到 left 和 right 指向同一元素为止
        while( left < right ){

            // 当 pivot + strs[right] 的字符串小于 strs[right] + pivot 的字符串时
            // 说明 strs[right] 在正确的位置上,right 向左移动
            // 1  3 
            while( left < right && (pivot + strs[right]).compareTo(strs[right] + pivot) <= 0 ){
                // right 不断的向左移动
                right--;
            }

            // 此时,跳出了上面这个 while 循环,说明 pivot + strs[right] 的字符串大于 strs[right] + pivot 的字符串了
            // 说明 strs[right] 不在正确的位置上
            // 将此时的 strs[left] 赋值为 strs[right]
            // 执行完这个操作,比 pivot 小的这个元素被移动到了左侧
            strs[left] = strs[right];

            // 当 strs[left] + pivot 的字符串小于 pivot + strs[left] 的字符串时
            // 说明 strs[left] 在正确的位置上,left 向右移动
            while( left < right &&  (strs[left] + pivot ).compareTo(pivot+ strs[left]) <= 0  ){
                // left 不断的向右移动
                left++;
            }

            // 此时,跳出了上面这个 while 循环,说明 strs[left] + pivot 的字符串大于 pivot + strs[left] 的字符串了
            // 说明 strs[left] 不在正确的位置上
            // 将此时的 strs[right] 赋值为 strs[left]
            // 执行完这个操作,比 pivot 大的这个元素被移动到了右侧
            strs[right] = strs[left];

        }

        // 此时,left 和 right 相遇,那么需要将此时的元素设置为 pivot
        // 这个时候,pivot 的左侧元素都小于它,右侧元素都大于它
        strs[left] = pivot;

        // 返回 left
        return left;

    }
}

# **2、**C++ 代码


# 3、Python 代码

登录 AlgoMooc 官网获取更多算法图解
# https://www.algomooc.com
# 作者:程序员吴师兄
# 代码有看不懂的地方一定要私聊咨询吴师兄呀
# https://leetcode-cn.com/problems/largest-number/
class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        
        # 先将 nums 转换为字符串数组的形式
        strs = [str(num) for num in nums]

        # 通过快速排序的方式,将字符串数组的每个字符按照约定的顺序进行排序
        self.quickSort(strs,0,len(strs) - 1)

        strs.reverse()
        
        # 再把字符串数组转字符串的形式  
        return ''.join(strs) if strs[0] != '0' else '0'

    # 函数传入待排序数组 nums
    # 排序区间的左端点 left
    # 排序区间的右端点 right
    def quickSort(self,strs: List[str] , left : int ,right : int) : 

        # 如果 left 大于等于 right,说明该区间只有 1 个或者没有元素
        if left >= right :
            # 无需再递归划分后再排序,直接返回
            return
        

        # 调用函数 partition,将 left 和 right 之间的元素划分为左右两部分
        mid = self.partition(strs,left,right)

        # 划分之后,再对 mid 左侧的元素进行快速排序
        self.quickSort(strs,left,mid-1)

        # 划分之后,再对 mid 右侧的元素进行快速排序
        self.quickSort(strs,mid+1,right)

    # 直接套之前的快速排序的代码进行修改
    # 原先的小于的含义指的是数值上的小于,比如 1  < 10 
    # 但现在的小于含义为:a + b 拼凑的字符串小于 b + a 拼凑的字符串
    # 比如 a = 1 ,b = 10 
    # 那么 a + b = “110”,b + a = “101”
    # 显然,b + a < a + b
    # 也就是说 a 应该放到 b 的后面来拼凑字符串
    def partition( self,strs: List[str] , left : int ,right) -> int : 

        # 经典快速排序的写法
        # 设置当前区间的第一个元素为基准元素
        pivot = strs[left]

        # left 向右移动,right 向左移动,直到 left 和 right 指向同一元素为止
        while left < right : 

            # 当 pivot + strs[right] 的字符串小于 strs[right] + pivot 的字符串时
            # 说明 strs[right] 在正确的位置上,right 向左移动
            # 1  3 
            while  left < right and pivot + strs[right] <=  strs[right] + pivot :
                # right 不断的向左移动
                right -= 1
    

            # 此时,跳出了上面这个 while 循环,说明 pivot + strs[right] 的字符串大于 strs[right] + pivot 的字符串了
            # 说明 strs[right] 不在正确的位置上
            # 将此时的 strs[left] 赋值为 strs[right]
            # 执行完这个操作,比 pivot 小的这个元素被移动到了左侧
            strs[left] = strs[right]

            # 当 strs[left] + pivot 的字符串小于 pivot + strs[left] 的字符串时
            # 说明 strs[left] 在正确的位置上,left 向右移动
            while  left < right and  strs[left] + pivot <= pivot+ strs[left] : 
                # left 不断的向右移动
                left+=1
        

            # 此时,跳出了上面这个 while 循环,说明 strs[left] + pivot 的字符串大于 pivot + strs[left] 的字符串了
            # 说明 strs[left] 不在正确的位置上
            # 将此时的 strs[right] 赋值为 strs[left]
            # 执行完这个操作,比 pivot 大的这个元素被移动到了右侧
            strs[right] = strs[left]

    

        # 此时,left 和 right 相遇,那么需要将此时的元素设置为 pivot
        # 这个时候,pivot 的左侧元素都小于它,右侧元素都大于它
        strs[left] = pivot

        # 返回 left
        return left